﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Reflection;

using Microsoft.Xna.Framework;

namespace tactics
{
    using RuleSet = Dictionary<string, TileInfo>;

    public enum TerrainRule
    {
        Open,       // anyone can cross
        Impassable, // impassable by all
        Blocked,    // flyers and tunnelers can cross but not stop on
        Difficult,  // standard-movement units take movement penalties
        VeryDifficult,  // standard-movement units take additional movement penalties, pathfinders take penalities
        Wall,       // only burrower units can pass (floor-to-ceiling wall)
    }

    // automagically generated struct-like class
    public class TileInfo
    {
        public TerrainRule MovementRule { get; set; }
        public Vector2[] TexCoords { get; set; }
        public TileInfo()
        {
            TexCoords = new Vector2[2];
        }
    }

    public class TileSet
    {
        string xmlFile;
        
        string name;
        string effectFile;
        string texture;
        int gridWidth;

        RuleSet ruleSet;

        #region Properties

        public string Name
        {
            get { return name; }
        }

        public string Effect
        {
            get { return effectFile; }
        }

        public string Texture
        {
            get { return texture; }
        }

        public int GridWidth
        {
            get { return gridWidth; }
        }

        public List<string> TileTypes
        {
            get
            {
                List<string> keys = new List<string>();

                foreach (var key in ruleSet.Keys)
                {
                    keys.Add(key);
                }

                return keys;
            }
        }

        #endregion

        public TileSet(string xmlFileIn)
        {
            xmlFile = xmlFileIn;

            ruleSet = new RuleSet();

            ParseTileSet();
        }

        #region Accessors

        public TerrainRule GetTileMovementRule(string tile)
        {
            return ruleSet[tile].MovementRule;
        }

        public TileInfo GetTileInfo(string tile)
        {
            return ruleSet[tile];
        }

        #endregion

        #region Parsing Infrastructure

        private void ParseTileSet()
        {
            TerrainRule tr = TerrainRule.Blocked;

            XmlDocument doc = new XmlDocument();
            doc.Load(xmlFile);

            // check if this is a proper xml file
            XmlNodeList root = doc.GetElementsByTagName("TileSet");
            if (root.Count == 0)
                return;

            name = root[0].Attributes["name"].Value;
            effectFile = root[0].Attributes["effect"].Value;
            texture = root[0].Attributes["texture"].Value;
            gridWidth = int.Parse(root[0].Attributes["gridwidth"].Value);

            foreach (XmlNode node in root[0].ChildNodes)
            {
                tr = GetTerrainRuleFromString(node.Name);
                foreach (XmlNode innerNode in node)
                    ParseRuleType(tr, innerNode);
            }
        }

        private void ParseRuleType(TerrainRule tr, XmlNode node)
        {
            if (!ruleSet.ContainsKey(node.Name))
                ruleSet[node.Name] = new TileInfo();

            ruleSet[node.Name].MovementRule = tr;
            ruleSet[node.Name].TexCoords[0].X = float.Parse(node.Attributes["x1"].Value);
            ruleSet[node.Name].TexCoords[0].Y = float.Parse(node.Attributes["y1"].Value);
            ruleSet[node.Name].TexCoords[1].X = float.Parse(node.Attributes["x2"].Value);
            ruleSet[node.Name].TexCoords[1].Y = float.Parse(node.Attributes["y2"].Value);
        }

        private TerrainRule GetTerrainRuleFromString(string rule)
        {
            TerrainRule tr = TerrainRule.Impassable;
            FieldInfo fi = (tr.GetType()).GetField(rule);

            if (fi != null)
                tr = (TerrainRule)Enum.Parse(typeof(TerrainRule), rule);

            return tr;
        }

        #endregion
    }
}
